/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import {
    AnyType,
    ArkArrayRef,
    ArkAssignStmt,
    ArkCastExpr,
    ArkClass,
    ArkField,
    ArkFile,
    ArkInstanceFieldRef,
    ArkInstanceInvokeExpr,
    ArkMethod,
    ArkNewArrayExpr,
    ArkNormalBinopExpr,
    ArkStaticFieldRef,
    ArkStaticInvokeExpr,
    ArrayType,
    AstTreeUtils,
    ClassType,
    Local,
    Stmt,
    StringType,
    ts,
    Type, TypeInference,
    UnknownType,
    Value
} from "arkanalyzer";
import Logger, { LOG_MODULE_TYPE } from 'arkanalyzer/lib/utils/logger';
import { FileMatcher, MatcherCallback, MatcherTypes, StmtMatcher } from "../../matcher/Matchers";
import { Defects, IssueReport } from "../../model/Defects";
import { Rule } from "../../model/Rule";
import { isAppointType } from "../../utils/checker/TypeUtils";
import { RuleListUtil } from "../../utils/common/DefectsList";
import { BaseChecker, BaseMetaData } from "../BaseChecker";
import { NumberConstant } from "arkanalyzer/lib/core/base/Constant";
import { CompositeMatcher } from '../../matcher/matcherAdapter/matchCommon';
import { FullPosition } from 'arkanalyzer/lib';

const logger = Logger.getLogger(LOG_MODULE_TYPE.HOMECHECK, 'NoUnsafeAssignmentCheck');
const gMetaData: BaseMetaData = {
    severity: 2,
    ruleDocPath: "docs/no-unsafe-assignment.md",
    description: "Disallow assigning a value with type `any` to variables and properties.",
};

export class NoUnsafeAssignmentCheck implements BaseChecker {
    public defects: Defects[] = [];
    public issues: IssueReport[] = [];
    readonly metaData: BaseMetaData = gMetaData;
    public rule: Rule;
    private fileMatcher: FileMatcher = {
        matcherType: MatcherTypes.FILE,
        match(node: ArkFile): boolean {
            return node.getName().endsWith('.ts');
        }
    };

    private stmtMatcher: StmtMatcher = {
        matcherType: MatcherTypes.STMT,
        match(stmt: Stmt): boolean {
            return stmt instanceof ArkAssignStmt;
        }
    };

    public registerMatchers(): MatcherCallback[] {
        const fileMatcherCb: MatcherCallback = {
            matcher: new CompositeMatcher([this.fileMatcher, this.stmtMatcher]),
            callback: this.check
        }
        return [fileMatcherCb];
    }

    public check = (stmt: ArkAssignStmt): void => {
        const rightType = stmt.getRightOp().getType();
        //检查赋值类型中是否含有any
        if (TypeInference.checkType(rightType, (t) => t instanceof AnyType)) {
            const position = stmt.getOperandOriginalPosition(stmt.getRightOp());
            if (!position) {
                return;
            }
            const filePath = stmt.getCfg()?.getDeclaringMethod().getDeclaringArkFile().getFilePath();
            this.addIssueReport(position, filePath);
        }
    }

    private addIssueReport(pos: FullPosition, filePath: string): void {
        const severity = this.rule.alert ?? this.metaData.severity;
        const message = 'Unsafe assignment of an `any` value.';
        let defects = new Defects(pos.getFirstLine(), pos.getFirstCol(), pos.getLastCol(), message, severity, this.rule.ruleId,
            filePath, this.metaData.ruleDocPath, true, false, false);
        this.issues.push(new IssueReport(defects, undefined));
        RuleListUtil.push(defects);
    }

}
